﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Ivony.Data;
using System.Data;
using System.Globalization;

namespace XCommunity.Documents
{
  public class DocumentPersister
  {

    private static readonly SqlDbUtility DbUtility = new SqlDbUtility( @"Data Source=(local);Initial Catalog=XCommunity;Integrated Security=True" );


    private DocumentService _service;

    public DocumentService Service
    {
      get { return _service; }
    }

    public DocumentPersister( DocumentService service )
    {
      _service = service;
    }


    /// <summary>
    /// 保存新文档
    /// </summary>
    /// <param name="document"></param>
    public void SaveDocument( Document document )
    {
      PersistData persist = SaveMeta( document );

      using ( Stream stream = GetSaveStream( persist ) )
      {
        document.SaveDocument( stream );
      }
      document.Meta.Saved = true;
    }

    /// <summary>
    /// 在子类实现时，返回一个流用于写入文档内容
    /// </summary>
    /// <param name="persist"></param>
    /// <returns></returns>
    protected virtual Stream GetSaveStream( PersistData persist )
    {
      string filepath = Path.Combine( @"C:\XCommunity\Documents", string.Format( "{0}.document", persist.PersistIdentity ) );

      return new FileStream( filepath, FileMode.Create, FileAccess.Write, FileShare.None );
    }


    /// <summary>
    /// 在子类实现时，用于保存文档的元数据和索引数据
    /// </summary>
    /// <param name="document"></param>
    /// <returns></returns>
    protected virtual PersistData SaveMeta( Document document )
    {

      Guid guid = Guid.NewGuid();
      string persistId = guid.ToString();

      DocumentMeta documentMeta = document.Meta;
      int documentId = Convert.ToInt32( DbUtility.ExecuteScalar( "INSERT INTO Documents ( Guid, Caption, Author, PersistId, DocumentType, SaveDate ) VALUES( {0}, {1}, {2}, {3}, {4}, {5} ); SELECT @@Identity", guid, documentMeta.Caption, documentMeta.Author, persistId, document.DocumentType, DateTime.UtcNow ) );

      documentMeta.DocumentId = documentId;

      return new PersistData()
      {
        DocumentId = documentId,
        PersistIdentity = persistId
      };
    }

    /// <summary>
    /// 加载文档
    /// </summary>
    /// <param name="documentId"></param>
    /// <returns></returns>
    public Document LoadDocument( int documentId )
    {
      PersistData persist = LoadPersisteData( documentId );

      DocumentMeta meta = new DocumentMeta();
      meta.Author = persist.Meta.Author;
      meta.Caption = persist.Meta.Caption;
      meta.DocumentId = persist.DocumentId;
      meta.Saved = true;

      Document document = CreateDocumentInstance( GetDocumentType( persist.Meta.DocumentType ), meta );

      document.LoadDocument( CreateLoadStream( persist ) );

      return document;
    }

    /// <summary>
    /// 在子类实现时，负责加载文档的持久化信息
    /// </summary>
    /// <param name="documentId"></param>
    /// <returns></returns>
    protected virtual PersistData LoadPersisteData( int documentId )
    {
      DataRow persistDataItem = DbUtility.ExecuteSingleRow( "SELECT ID, Caption, Author, PersistId, DocumentType FROM Documents WHERE ID = {0}", documentId );

      return new PersistData()
      {
        DocumentId = (int) persistDataItem["ID"],
        PersistIdentity = (string) persistDataItem["PersistId"],

        Meta = new PersistDocumentMeta()
        {
          DocumentType = (string) persistDataItem["DocumentType"],
          Author = (string) persistDataItem["Author"],
          Caption = (string) persistDataItem["Caption"]
        }
      };
    }


    /// <summary>
    /// 根据文档类型名获取具体的文档类型
    /// </summary>
    /// <param name="typeName"></param>
    /// <returns></returns>
    protected virtual Type GetDocumentType( string typeName )
    {
      return Type.GetType( typeName );
    }


    /// <summary>
    /// 创建文档对象实例
    /// </summary>
    /// <param name="documentType">文档对象类型</param>
    /// <param name="meta">文档元数据</param>
    /// <returns></returns>
    private Document CreateDocumentInstance( Type documentType, DocumentMeta meta )
    {
      var constructor = documentType.GetConstructor( new Type[] { typeof( DocumentMeta ) } );
      return (Document) constructor.Invoke( new object[] { meta } );
    }

    /// <summary>
    /// 在子类实现时，返回一个流用于加载文档内容
    /// </summary>
    /// <param name="persist">持久化数据</param>
    /// <returns></returns>
    private Stream CreateLoadStream( PersistData persist )
    {
      string filepath = Path.Combine( @"C:\XCommunity\Documents", string.Format( CultureInfo.InvariantCulture, "{0}.document", persist.PersistIdentity ) );

      return new FileStream( filepath, FileMode.Open, FileAccess.Read, FileShare.Read );
    }



    protected class PersistData
    {

      public int DocumentId
      {
        get;
        set;
      }

      public string PersistIdentity
      {
        get;
        set;
      }

      public PersistDocumentMeta Meta
      {
        get;
        set;
      }

    }

    protected class PersistDocumentMeta
    {
      public string Author
      {
        get;
        set;
      }

      public string Caption
      {
        get;
        set;
      }

      public string DocumentType
      {
        get;
        set;
      }

    }

  }
}
